`timescale 1ns / 1ps
/******************************************************************************
*                                                                             *
* UTICA softcore v0.1                                                         *
*                                                                             *
* Copyright (c) 2012 Andrew D. Zonenberg                                      *
* All rights reserved.                                                        *
*                                                                             *
* Redistribution and use in source and binary forms, with or without modifi-  *
* cation, are permitted provided that the following conditions are met:       *
*                                                                             *
*    * Redistributions of source code must retain the above copyright notice  *
*      this list of conditions and the following disclaimer.                  *
*                                                                             *
*    * Redistributions in binary form must reproduce the above copyright      *
*      notice, this list of conditions and the following disclaimer in the    *
*      documentation and/or other materials provided with the distribution.   *
*                                                                             *
*    * Neither the name of the author nor the names of any contributors may be*
*      used to endorse or promote products derived from this software without *
*      specific prior written permission.                                     *
*                                                                             *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF        *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN     *
* NO EVENT SHALL THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT,         *
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT    *
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,   *
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY       *
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT         *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF    *
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.           *
*                                                                             *
******************************************************************************/
module testL1Cache;

	// Inputs
	reg clk;
	reg [31:0] cpu_addr;
	reg cpu_rd;
	reg cpu_wr;
	reg [31:0] cpu_dout;
	reg [3:0] cpu_wmask;
	reg [31:0] l2_dout;
	reg l2_dinok;

	// Outputs
	wire [31:0] cpu_din;
	wire cpu_dinok;
	wire [31:0] l2_addr;
	wire l2_rd;
	wire l2_wr;
	wire [3:0] l2_wmask;
	wire [31:0] l2_din;

	// Instantiate the Unit Under Test (UUT)
	L1Cache uut (
		.clk(clk), 
		.cpu_addr(cpu_addr), 
		.cpu_rd(cpu_rd), 
		.cpu_wr(cpu_wr), 
		.cpu_dout(cpu_dout), 
		.cpu_wmask(cpu_wmask), 
		.cpu_din(cpu_din), 
		.cpu_dinok(cpu_dinok), 
		.l2_addr(l2_addr), 
		.l2_rd(l2_rd), 
		.l2_wr(l2_wr), 
		.l2_dout(l2_dout), 
		.l2_wmask(l2_wmask), 
		.l2_din(l2_din), 
		.l2_dinok(l2_dinok)
	);

	reg ready = 0;
	initial begin
		// Initialize Inputs
		clk = 0;
		cpu_addr = 0;
		cpu_rd = 0;
		cpu_wr = 0;
		cpu_dout = 0;
		cpu_wmask = 0;
		l2_dout = 0;
		l2_dinok = 0;

		// Wait 100 ns for global reset to finish
		#100;
      ready = 1;
	end
	
	always begin
		#5;
		clk = ready;
		#5;
		clk = 0;
		if(ready)
			$display("--- CLOCK ---");
	end
	
	//Request generator
	reg[15:0] testcount = 0;
	always @(posedge clk) begin
	
		cpu_addr <= 0;
		cpu_rd <= 0;
		cpu_wr <= 0;
		cpu_dout <= 0;
		cpu_wmask <= 0;
	
		case(testcount)
		
			//Word write to an uncached address
			0: begin
				cpu_addr <= 32'hb0000104;
				cpu_wr <= 1;
				cpu_dout <= 32'hdeadbeef;
				cpu_wmask <= 4'b1111;
				testcount <= 1;
			end
			
			//Word write to a cached address
			1: begin
				cpu_addr <= 32'h90000000;
				cpu_wr <= 1;
				cpu_dout <= 32'hbaadc0de;
				cpu_wmask <= 4'b1111;
				testcount <= 2;
			end
			
			//Word read from an uncached address
			2: begin
				cpu_addr <= 32'hb0000104;
				cpu_rd <= 1;
				testcount <= 3;
			end
			
			//Word read from a cached address
			3: begin
				cpu_addr <= 32'h90000000;
				cpu_rd <= 1;
				
				testcount <= 4;
			end
			
			//Verify read #2 turned out OK
			//Write to another address that will hit the same cache line as the last one
			4: begin
				if(cpu_dinok && cpu_din == 32'h4ffffefb)
					$display("read OK");
				else
					$display("something is wrong");
					
				cpu_addr <= 32'h91000000;
				cpu_wr <= 1;
				cpu_dout <= 32'hfeedface;
				cpu_wmask <= 4'b1111;
					
				testcount <= 5;
			end
			
			//Verify read #3 turned out OK
			//then try reading from the original address. Should miss since the data isnt there yet
			5: begin
			
				if(cpu_dinok && cpu_din == 32'hbaadc0de)
					$display("read OK");
				else
					$display("something is wrong");

				cpu_addr <= 32'h90000000;
				cpu_rd <= 1;
			
				testcount <= 6;
			
			end
			
			//Wait for read
			6: begin
				testcount <= 7;
			end
			
			//See if the read was a hit or not
			7: begin
				if(cpu_dinok) begin
					if(cpu_din == 32'h6fffffff)
						$display("cache hit, read OK");
					else
						$display("something is wrong");
					testcount <= 8;
				end
				
				//It's a miss, go fetch it again
				else begin
					$display("cache miss");
					cpu_addr <= 32'h90000000;
					cpu_rd <= 1;
					testcount <= 6;
				end
			end
			
			//Stall forever
			8: begin
			end
		
		endcase
	end
	
	//Fake L2
	always @(posedge clk) begin
		
		l2_dout <= 0;
		l2_dinok <= 0;
		
		if(l2_wr) begin
			$display("[FakeL2Cache]  Writing 0x%x to address 0x%x wmask %b", l2_din, l2_addr, l2_wmask);
		end
		
		if(l2_rd) begin
			$display("[FakeL2Cache]  Reading from address 0x%x, returning 0x%x", l2_addr, ~l2_addr);
			l2_dout <= ~l2_addr;
			l2_dinok <= 1;
		end
		
	end
      
endmodule

